package com.xiaomo.gitee.datamanager.config;

import com.xiaomo.gitee.datamanager.mapper.RoleMapper;
import com.xiaomo.gitee.datamanager.entity.Role;
import com.xiaomo.gitee.datamanager.security.MyPasswordEncoder;
import com.xiaomo.gitee.datamanager.security.filter.JwtAuthenticationFilter;
import com.xiaomo.gitee.datamanager.security.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    private final RoleMapper roleMapper;
    private final DataSource dataSource;

    private final LoginSuccessHandler loginSuccessHandler;
    private final LogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    public SecurityConfig(LogoutSuccessHandler logoutSuccessHandler,LoginSuccessHandler loginSuccessHandler,RoleMapper roleMapper, DataSource dataSource) {
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.loginSuccessHandler = loginSuccessHandler;
        this.roleMapper = roleMapper;
        this.dataSource = dataSource;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http,AuthenticationConfiguration authenticationConfiguration) throws Exception {
        http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> {
            authorizationManagerRequestMatcherRegistry
                    .requestMatchers("/error/**", "/login/**","/static/**", "/login-api","/logout","/api/main-menu","/docs-api/**").permitAll()
                    .requestMatchers("/swagger-ui/**","/doc.html","/doc.html#/**").hasRole("admin")
                    .anyRequest().authenticated();

        });

        http.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
            httpSecurityExceptionHandlingConfigurer
                    .accessDeniedHandler(new AccessDeniedHandler())
                    .authenticationEntryPoint(new AuthenticationFailureHandler());
        });

        http.formLogin(httpSecurityFormLoginConfigurer -> {
            httpSecurityFormLoginConfigurer
                    .loginPage("/login")
                    .passwordParameter("password")
                    .usernameParameter("username")
                    .loginProcessingUrl("/login")
                    //.defaultSuccessUrl("/index")
                    .successHandler(loginSuccessHandler)
                    .failureHandler(new LoginFailureHandler());

        });

        http.logout(httpSecurityLogoutConfigurer -> {
            httpSecurityLogoutConfigurer
                    .invalidateHttpSession(true)
                    .clearAuthentication(true)
                    .logoutUrl("/logout")
                    //.logoutSuccessUrl("/login")
                    .logoutSuccessHandler(logoutSuccessHandler);
        });

        http.rememberMe(httpSecurityRememberMeConfigurer -> {
            httpSecurityRememberMeConfigurer
                    .alwaysRemember(false);
        });

        http.sessionManagement(httpSecuritySessionManagementConfigurer -> {
            httpSecuritySessionManagementConfigurer
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        });
        http.csrf(AbstractHttpConfigurer::disable);

        http.addFilter(new JwtAuthenticationFilter(authenticationConfiguration.getAuthenticationManager()));

        return http.build();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    @Bean
    public Role defaultRole() {
        return roleMapper.selectOneByName("user");
    }

}
